package com.cencat.common.utils;

import java.security.SecureRandom;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;

import com.cencat.common.utils.CencatStringUtils;

/**
 * ID生成工具类
 * 提供各种ID生成方法
 * 
 * @author cencat
 * @since 2024-01-01
 */
public class IdUtils {

    /**
     * 雪花算法实例
     */
    private static final SnowflakeIdGenerator SNOWFLAKE = new SnowflakeIdGenerator(1, 1);

    /**
     * 安全随机数生成器
     */
    private static final SecureRandom SECURE_RANDOM = new SecureRandom();

    /**
     * 私有构造函数，防止实例化
     */
    private IdUtils() {
    }

    /**
     * 生成UUID（去掉横线）
     * 
     * @return UUID字符串
     */
    public static String uuid() {
        return UUID.randomUUID().toString().replace("-", "");
    }

    /**
     * 生成标准UUID（带横线）
     * 
     * @return UUID字符串
     */
    public static String standardUuid() {
        return UUID.randomUUID().toString();
    }

    /**
     * 生成雪花ID
     * 
     * @return 雪花ID
     */
    public static long snowflakeId() {
        return SNOWFLAKE.nextId();
    }

    /**
     * 生成雪花ID字符串
     * 
     * @return 雪花ID字符串
     */
    public static String snowflakeIdStr() {
        return String.valueOf(SNOWFLAKE.nextId());
    }

    /**
     * 生成时间戳ID
     * 
     * @return 时间戳ID
     */
    public static long timestampId() {
        return System.currentTimeMillis();
    }

    /**
     * 生成时间戳ID字符串
     * 
     * @return 时间戳ID字符串
     */
    public static String timestampIdStr() {
        return String.valueOf(System.currentTimeMillis());
    }

    /**
     * 生成纳秒时间戳ID
     * 
     * @return 纳秒时间戳ID
     */
    public static long nanoTimestampId() {
        return System.nanoTime();
    }

    /**
     * 生成随机数字ID
     * 
     * @param length 长度
     * @return 随机数字ID
     */
    public static String randomNumericId(int length) {
        if (length <= 0) {
            return "";
        }
        
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < length; i++) {
            sb.append(ThreadLocalRandom.current().nextInt(10));
        }
        return sb.toString();
    }

    /**
     * 生成随机字符串ID
     * 
     * @param length 长度
     * @return 随机字符串ID
     */
    public static String randomStringId(int length) {
        if (length <= 0) {
            return "";
        }
        
        String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        StringBuilder sb = new StringBuilder();
        
        for (int i = 0; i < length; i++) {
            int index = ThreadLocalRandom.current().nextInt(chars.length());
            sb.append(chars.charAt(index));
        }
        
        return sb.toString();
    }

    /**
     * 生成安全随机字符串ID
     * 
     * @param length 长度
     * @return 安全随机字符串ID
     */
    public static String secureRandomStringId(int length) {
        if (length <= 0) {
            return "";
        }
        
        String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        StringBuilder sb = new StringBuilder();
        
        for (int i = 0; i < length; i++) {
            int index = SECURE_RANDOM.nextInt(chars.length());
            sb.append(chars.charAt(index));
        }
        
        return sb.toString();
    }

    /**
     * 生成订单号
     * 格式：yyyyMMddHHmmss + 6位随机数
     * 
     * @return 订单号
     */
    public static String orderNo() {
        String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
        String random = randomNumericId(6);
        return timestamp + random;
    }

    /**
     * 生成订单号（带前缀）
     * 
     * @param prefix 前缀
     * @return 订单号
     */
    public static String orderNo(String prefix) {
        if (CencatStringUtils.isBlank(prefix)) {
            return orderNo();
        }
        return prefix + orderNo();
    }

    /**
     * 生成流水号
     * 格式：yyyyMMddHHmmssSSS + 4位随机数
     * 
     * @return 流水号
     */
    public static String serialNo() {
        String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS"));
        String random = randomNumericId(4);
        return timestamp + random;
    }

    /**
     * 生成流水号（带前缀）
     * 
     * @param prefix 前缀
     * @return 流水号
     */
    public static String serialNo(String prefix) {
        if (CencatStringUtils.isBlank(prefix)) {
            return serialNo();
        }
        return prefix + serialNo();
    }

    /**
     * 生成批次号
     * 格式：yyyyMMdd + 8位随机数
     * 
     * @return 批次号
     */
    public static String batchNo() {
        String date = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        String random = randomNumericId(8);
        return date + random;
    }

    /**
     * 生成批次号（带前缀）
     * 
     * @param prefix 前缀
     * @return 批次号
     */
    public static String batchNo(String prefix) {
        if (CencatStringUtils.isBlank(prefix)) {
            return batchNo();
        }
        return prefix + batchNo();
    }

    /**
     * 生成请求ID
     * 
     * @return 请求ID
     */
    public static String requestId() {
        return uuid();
    }

    /**
     * 生成会话ID
     * 
     * @return 会话ID
     */
    public static String sessionId() {
        return uuid();
    }

    /**
     * 生成追踪ID
     * 
     * @return 追踪ID
     */
    public static String traceId() {
        return uuid();
    }

    /**
     * 雪花算法ID生成器
     */
    public static class SnowflakeIdGenerator {
        
        /**
         * 起始时间戳（2024-01-01 00:00:00）
         */
        private static final long START_TIMESTAMP = 1704067200000L;
        
        /**
         * 机器ID位数
         */
        private static final long WORKER_ID_BITS = 5L;
        
        /**
         * 数据中心ID位数
         */
        private static final long DATACENTER_ID_BITS = 5L;
        
        /**
         * 序列号位数
         */
        private static final long SEQUENCE_BITS = 12L;
        
        /**
         * 机器ID最大值
         */
        private static final long MAX_WORKER_ID = ~(-1L << WORKER_ID_BITS);
        
        /**
         * 数据中心ID最大值
         */
        private static final long MAX_DATACENTER_ID = ~(-1L << DATACENTER_ID_BITS);
        
        /**
         * 序列号最大值
         */
        private static final long MAX_SEQUENCE = ~(-1L << SEQUENCE_BITS);
        
        /**
         * 机器ID左移位数
         */
        private static final long WORKER_ID_SHIFT = SEQUENCE_BITS;
        
        /**
         * 数据中心ID左移位数
         */
        private static final long DATACENTER_ID_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS;
        
        /**
         * 时间戳左移位数
         */
        private static final long TIMESTAMP_LEFT_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS + DATACENTER_ID_BITS;
        
        /**
         * 机器ID
         */
        private final long workerId;
        
        /**
         * 数据中心ID
         */
        private final long datacenterId;
        
        /**
         * 序列号
         */
        private long sequence = 0L;
        
        /**
         * 上次生成ID的时间戳
         */
        private long lastTimestamp = -1L;
        
        /**
         * 构造函数
         * 
         * @param workerId 机器ID
         * @param datacenterId 数据中心ID
         */
        public SnowflakeIdGenerator(long workerId, long datacenterId) {
            if (workerId > MAX_WORKER_ID || workerId < 0) {
                throw new IllegalArgumentException(String.format("Worker ID can't be greater than %d or less than 0", MAX_WORKER_ID));
            }
            if (datacenterId > MAX_DATACENTER_ID || datacenterId < 0) {
                throw new IllegalArgumentException(String.format("Datacenter ID can't be greater than %d or less than 0", MAX_DATACENTER_ID));
            }
            
            this.workerId = workerId;
            this.datacenterId = datacenterId;
        }
        
        /**
         * 生成下一个ID
         * 
         * @return ID
         */
        public synchronized long nextId() {
            long timestamp = timeGen();
            
            if (timestamp < lastTimestamp) {
                throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
            }
            
            if (lastTimestamp == timestamp) {
                sequence = (sequence + 1) & MAX_SEQUENCE;
                if (sequence == 0) {
                    timestamp = tilNextMillis(lastTimestamp);
                }
            } else {
                sequence = 0L;
            }
            
            lastTimestamp = timestamp;
            
            return ((timestamp - START_TIMESTAMP) << TIMESTAMP_LEFT_SHIFT)
                    | (datacenterId << DATACENTER_ID_SHIFT)
                    | (workerId << WORKER_ID_SHIFT)
                    | sequence;
        }
        
        /**
         * 等待下一毫秒
         * 
         * @param lastTimestamp 上次时间戳
         * @return 当前时间戳
         */
        protected long tilNextMillis(long lastTimestamp) {
            long timestamp = timeGen();
            while (timestamp <= lastTimestamp) {
                timestamp = timeGen();
            }
            return timestamp;
        }
        
        /**
         * 获取当前时间戳
         * 
         * @return 当前时间戳
         */
        protected long timeGen() {
            return System.currentTimeMillis();
        }
    }
}